package nio.common.cs.client;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit;

import org.apache.tomcat.jni.Thread;

public class Client {
    private static final int BUF_SIZE = 1024;
    private static final int PORT = 8088;
    private static final int TIMEOUT = 3000;
    private static int WRITE_TIMES = 1;
    private static ConcurrentLinkedQueue<String> messageList = new ConcurrentLinkedQueue<>();

    public static void main(String[] args) {
        new java.lang.Thread(new Runnable() {
            public void run() {
                Scanner sc = new Scanner(System.in);
                while (sc.hasNext()) {
                    messageList.offer(sc.next());
                }
            }
        }).start();
        client();
    }

    public static void client() {
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        SocketChannel socketChannel = null;
        try {
            Selector selector = Selector.open();
            socketChannel = SocketChannel.open();
            socketChannel.configureBlocking(false);
            socketChannel.connect(new InetSocketAddress("127.0.0.1", 8088));
            socketChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE, 1);
            // while (true) {
            if (socketChannel.finishConnect()) {
                buffer.clear();
                buffer.put("client first message".getBytes());
                buffer.flip();
                socketChannel.write(buffer);
            }
            // }
            while (true) {
                if (selector.select(TIMEOUT) == 0) {
                    System.out.println("in client timeout");
                    continue;
                }
                Iterator<SelectionKey> iter = selector.selectedKeys().iterator();
                while (iter.hasNext()) {
                    SelectionKey key = iter.next();
                    if (key.isAcceptable()) {
                        handleAccept(key);
                    }
                    if (key.isReadable()) {
                        handleRead(key);
                    }
                    if (key.isWritable() && key.isValid()) {
                        handleWrite(key);
                    }
                    if (key.isConnectable()) {
                        System.out.println("isConnectable = true");
                    }
                    iter.remove();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (socketChannel != null) {
                    socketChannel.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    public static void handleAccept(SelectionKey key) throws IOException {
        ServerSocketChannel ssChannel = (ServerSocketChannel) key.channel();
        SocketChannel sc = ssChannel.accept();
        sc.configureBlocking(false);
        System.err.println("in accept");
        sc.register(key.selector(), SelectionKey.OP_READ | SelectionKey.OP_WRITE, ByteBuffer.allocateDirect(BUF_SIZE));
    }

    public static void handleRead(SelectionKey key) throws IOException {
        System.out.println("in client read");
        SocketChannel sc = (SocketChannel) key.channel();
        ByteBuffer buf = ByteBuffer.allocate(1024);
        long bytesRead = sc.read(buf);
        while (bytesRead > 0) {
            buf.flip();
            while (buf.hasRemaining()) {
                System.out.print((char) buf.get());
            }
            System.out.println();
            buf.clear();
            bytesRead = sc.read(buf);
        }
        if (bytesRead == -1) {
            sc.close();
        }
    }

    public static void handleWrite(SelectionKey key) throws IOException {
        // System.out.println("in client write");
        ByteBuffer buf = ByteBuffer.allocate(1024);
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        // buf.put(("client`s message" + WRITE_TIMES).getBytes());
        // buf.flip();
        // SocketChannel sc = (SocketChannel) key.channel();
        // while (buf.hasRemaining()) {
        // sc.write(buf);
        // }
        // buf.compact();
        System.out.println("please input the message:");
        // System.out.println("键盘输入的内容是：" + sc.next());
        if (!messageList.isEmpty()) {
            buf.clear();
            String temp = messageList.poll();
            System.out.println("in list: " + temp);
            buf.put(temp.getBytes());
            buf.flip();
            SocketChannel socketChannel = (SocketChannel) key.channel();
            socketChannel.write(buf);
            buf.compact();
        }
    }

}
